/* Copyright (c) 2007-2008, Jeffrey R Griffin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Jeffrey R Griffin nor the
*       names of his contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Jeffrey R Griffin ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package net.visibleblue.android.paranoid;

import android.content.ContentProvider;
import android.content.ContentProviderDatabaseHelper;
import android.content.ContentURIParser;
import android.content.ContentValues;
import android.content.QueryBuilder;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.ContentURI;
import android.provider.BaseColumns;
import android.text.TextUtils;

public class Provider extends ContentProvider {
    
	private SQLiteDatabase _db;
	private static final ContentURIParser URL_MATCHER;
	private static final String TABLE_NAME = "publicKeys";
	private static final String DATABASE_NAME = "paranoid.db";
	private static final int DATABASE_VERSION = 1;
	private static final int KEYS = 1;
    private static final int KEYS_ID = 2;
	public static final ContentURI CONTENT_URI = 
		ContentURI.create( "content://net.visibleblue.android.paranoid.provider/"+TABLE_NAME);
	public static final String CONTACT_ID_COLUMN = "contactID";
	public static final String DIGEST_COLUMN = "digest";
	public static final String PUBLIC_KEY_ALGORITHM_COLUMN = "publicKeyAlgorithm";
	static final String DATA_COLUMN = "_data";
	public static final String DEFAULT_SORT_ORDER = CONTACT_ID_COLUMN+" DESC";
	
	static {
        URL_MATCHER = new ContentURIParser(ContentURIParser.NO_MATCH);
        URL_MATCHER.addURI("net.visibleblue.android.paranoid.provider", 
        		TABLE_NAME, KEYS);
        URL_MATCHER.addURI("net.visibleblue.android.paranoid.provider", 
        		TABLE_NAME+"/#", KEYS_ID);
	}
	
	@Override
	public boolean onCreate() {
		DatabaseHelper dbHelper = new DatabaseHelper();
        _db = dbHelper.openDatabase(getContext(), DATABASE_NAME, null, DATABASE_VERSION);
        return (_db == null) ? false : true;
	}

	@Override
	public int delete(ContentURI url, String selection,
			String[] selectionArgs) {
		int count = 0;
		switch (URL_MATCHER.match(url)) {
		case KEYS:
			count = _db.delete(TABLE_NAME, selection, selectionArgs);
			break;

		case KEYS_ID:
			String segment = url.getPathSegment(1);
			count = _db.delete(TABLE_NAME, BaseColumns._ID+"="+ segment
					+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
							+ ')' : ""), selectionArgs);
			break;

		}
		return count;
	}

	@Override
	public ContentURI insert(ContentURI url, ContentValues initialValues) {
		long rowID;
        ContentValues values;
        if (initialValues != null) {
            values = new ContentValues(initialValues);
        } else throw new IllegalArgumentException("initialValues argument cannot be null");

        if (URL_MATCHER.match(url) != KEYS) {
            throw new IllegalArgumentException("Unknown URL " + url);
        }
        
        // Make sure that the fields are all set
        if (values.containsKey(CONTACT_ID_COLUMN) == false) {
            values.put(CONTACT_ID_COLUMN, 0);
        }

        if (values.containsKey(DIGEST_COLUMN) == false) {
        	throw new IllegalArgumentException("Cannot insert a row without a digest");
        }
        
        // Make sure that the fields are all set
        if (values.containsKey(DATA_COLUMN) == false) {
            values.put(DATA_COLUMN, (String)null);
        }

        rowID = _db.insert(TABLE_NAME, null, values);
        if (rowID > 0) {
            ContentURI uri = CONTENT_URI.addId(rowID);
            getContext().getContentResolver().notifyChange(uri, null);
            return uri;
        }

        throw new SQLException("Failed to insert row into " + url);
	}

	@Override
	public Cursor query(ContentURI url, String[] projection,
			String selection, String[] selectionArgs, String groupBy,
			String having, String sortOrder) {

		QueryBuilder qb = new QueryBuilder();

		switch (URL_MATCHER.match(url)) {
		case KEYS:
			qb.setTables(TABLE_NAME);
			break;

		case KEYS_ID:
			qb.setTables(TABLE_NAME);
			qb.appendWhere(BaseColumns._ID+"=" + url.getPathSegment(1));
			break;

		default:
			throw new IllegalArgumentException("Unknown URL " + url);
		}

		// If no sort order is specified use the default
        String orderBy;
        if (TextUtils.isEmpty(sortOrder)) {
            orderBy = DEFAULT_SORT_ORDER;
        } else {
            orderBy = sortOrder;
        }

        Cursor c = qb.query(_db, projection, selection, selectionArgs, groupBy,
                having, orderBy);
        c.setNotificationUri(getContext().getContentResolver(), url);
        return c;
	}

	@Override
	public int update(ContentURI url, ContentValues values,
			String selection, String[] selectionArgs) {
		int count;
        switch (URL_MATCHER.match(url)) {
        case KEYS:
            count = _db.update(TABLE_NAME, values, selection, selectionArgs);
            break;

        case KEYS_ID:
            String segment = url.getPathSegment(1);
            count = _db.update(TABLE_NAME, values, BaseColumns._ID+"="+ segment
            		+ (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), 
            		selectionArgs);
            break;

        default:
            throw new IllegalArgumentException("Unknown URL " + url);
        }

        getContext().getContentResolver().notifyChange(url, null);
        return count;
	}

	@Override
	public String getType(ContentURI uri) {
		switch (URL_MATCHER.match(uri)) {
		case KEYS:
			return "vnd.visibleblue.cursor.dir/vnd.visibleblue.privateKey";

		case KEYS_ID:
			return "vnd.visibleblue.cursor.item/vnd.visibleblue.privateKey";

		default:
			throw new IllegalArgumentException("Unknown URL " + uri);
		}
	}
	
	private static class DatabaseHelper extends ContentProviderDatabaseHelper {

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL("CREATE TABLE "+Provider.TABLE_NAME+" ("
					+ BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ DIGEST_COLUMN + " TEXT UNIQUE," + CONTACT_ID_COLUMN+" INTEGER UNIQUE," 
					+ PUBLIC_KEY_ALGORITHM_COLUMN+" TEXT," + DATA_COLUMN+" TEXT" + ");");
		}

		@Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS "+Provider.TABLE_NAME);
            onCreate(db);
        }
	}
}
